package net.posick.ws.soap;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import net.posick.ws.xml.Name;
import net.posick.ws.xml.Namespace;
import net.posick.ws.xml.XmlElement;


public class SOAPFault extends SOAPBase
{
    private static final long serialVersionUID = 201403271221L;
    
    
    public static final String ELEMENT_NAME = "Fault";
    
    public static final Name FQN = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), ELEMENT_NAME);
    
    
    public static final Name NAME_FAULT_CODE = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), "faultcode");
    
    public static final Name NAME_FAULT_STRING = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), "faultstring");
    
    public static final Name NAME_FAULT_ACTOR = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), "faultactor");
    
    public static final Name NAME_FAULT_DETAIL = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), "detail");
    
    
    protected String faultCode = null;
    
    protected String faultString = null;
    
    protected String faultActor = null;
    
    protected XmlElement detail = null;
    
    
    public SOAPFault()
    {
        super(FQN);
    }
    
    
    public SOAPFault(String faultCode, String faultString, String faultActor, XmlElement detail)
    {
        super(FQN);
        this.faultCode = faultCode;
        this.faultString = faultString;
        this.faultActor = faultActor;
        
        addChild(new XmlElement(NAME_FAULT_CODE).setValue(faultCode));
        addChild(new XmlElement(NAME_FAULT_STRING).setValue(faultString));
        addChild(new XmlElement(NAME_FAULT_ACTOR).setValue(faultActor));
        
        if (detail != null)
        {
            Name name = detail.getName();
            String prefix = name.getPrefix();
            if (NAME_FAULT_DETAIL.equals(name) && (prefix == null || prefix.length() == 0))
            {
                this.detail = detail;
            } else
            {
                this.detail = new XmlElement(NAME_FAULT_DETAIL);
                this.detail.addChild(detail);
            }
            addChild(this.detail);
        }
    }


    public SOAPFault(XmlElement xml)
    throws SOAPException
    {
        super(FQN);
        
        Name name = xml.getName();
        
        if (FQN.equals(name))
        {
            List<XmlElement> elements = xml.getChildren();
            if (elements != null && elements.size() > 0)
            {
                for (XmlElement element : elements)
                {
                    name = xml.getName();
                    String prefix = name.getPrefix();
                    if (NAME_FAULT_CODE.equals(name) && (prefix == null || prefix.length() == 0))
                    {
                        faultCode = element.getValue().toString();
                        addChild(element);
                    } else if (NAME_FAULT_STRING.equals(name) && (prefix == null || prefix.length() == 0))
                    {
                        faultString = element.getValue().toString();
                        addChild(element);
                    } else if (NAME_FAULT_ACTOR.equals(name) && (prefix == null || prefix.length() == 0))
                    {
                        faultActor = element.getValue().toString();
                        addChild(element);
                    } else if (NAME_FAULT_DETAIL.equals(name) && (prefix == null || prefix.length() == 0))
                    {
                        detail = element;
                        addChild(element);
                    } else
                    {
                        throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Fault \"" + xml.getName() + "\". " + ERROR_MESSAGE_R1000);
                    }
                }
            } else
            {
                throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Fault \"" + xml.getName() + "\". " + ERROR_MESSAGE_R1000);
            }
        } else
        {
            throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Fault \"" + xml.getName() + "\".  Must be of type \"" + FQN + "\"");
        }
    }


    public SOAPFault(Throwable t)
    {
        this(t.getClass().getName(), t.getMessage(), t.getCause() != null ? t.getCause().getClass().getName() : null, generateDetail(t));
    }


    private static XmlElement generateDetail(Throwable t)
    {
        XmlElement xml = new XmlElement(NAME_FAULT_DETAIL);
        
        StringWriter writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        t.printStackTrace(printWriter);
        
        return xml.setValue(writer.toString());
    }
}
